﻿using BCAMap.AMap;
using BCAMap.Dto;
using BCCommon;
using BCCommon.Extensions;
using BCCommon.TMS.FreightEnums;
using BCCommon.TMS.Order;
using BCCommon.TMS.Transport;
using BCData.TMS.Order.Order;
using BCData.TMS.Order.OrderExtention;
using BCData.TMS.Order.OrderPool;
using BCData.TMS.OrderExtentionGoodsChecklist;
using BCData.TMS.OrderFreightAppendRecord;
using BCData.TMS.OrderFreightFormulaRecord;
using BCData.TMS.OrderFreightRecord;
using BCData.TMS.OrderPackingRecord;
using BCDto.MySql.FreightConfigurationExtention;
using BCDto.TMS.InsuredConfig;
using BCDto.TMS.MarketingCoupon.MarketingCoupon;
using BCDto.TMS.Order;
using BCDto.TMS.Order.Order;
using BCDto.TMS.OrderFreightAppendRecord;
using BCDto.TMS.Packing.PackingConfig;
using BCDto.TMS.TransportOrder;
using BCDto.TMS.VehicleBusinessMapping;
using BCEntity.Common.Area;
using BCEntity.TMS.Order.Order;
using BCEntity.TMS.Order.OrderExtention;
using BCEntity.TMS.Order.OrderPool;
using BCEntity.TMS.OrderExtentionGoodsChecklist;
using BCEntity.TMS.OrderFreightAppendRecord;
using BCEntity.TMS.OrderFreightFormulaRecord;
using BCEntity.TMS.OrderPackingRecord;
using BCService.Common.Area;
using BCService.CRM.BigCustomer;
using BCService.CRM.BigCustomerFreightConfigExtention;
using BCService.Sim.Company.Company;
using BCService.TMS.Agent.AgentAreaRecord;
using BCService.TMS.Agent.AgentRecord;
using BCService.TMS.FreightConfigurationExtention;
using BCService.TMS.FreightConfigurationService;
using BCService.TMS.InsuredConfig;
using BCService.TMS.MarketingCoupon.MarketingCoupon;
using BCService.TMS.MarketingCoupon.MarketingCouponReceive;
using BCService.TMS.MarketingCoupon.MarketingCouponUsing;
using BCService.TMS.NightFreightConfiguration;
using BCService.TMS.Packing.PackingConfig;
using BCService.TMS.Packing.PackingConfigOverwrite;
using BCService.TMS.TransportOrder;
using BCService.TMS.VehicleBusinessMappingOverwrite;
using BCService.TMS.VehicleTransportBusinessConfig;
using BCService.TMS.VehicleTypeService;
using BCService.Utils;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;

namespace BCService.TMS.Order.Order
{
    public class SmallPiecesOrderService : IOrderService
    {
        private readonly IDatabaseContext databaseContext;
        private readonly IConfiguration configuration;
        private readonly IZoneService zoneService;
        private readonly IAMapUtils aMapUtils;
        private readonly ICompanyService companyService;
        private readonly IAgentRecordService agentRecordService;
        private readonly IAgentAreaRecordService agentAreaRecordService;
        private readonly ITransportOrderService transportOrderService;
        private readonly IVehicleTransportBusinessConfigService vehicleTransportBusinessConfigService;
        private readonly IVehicleBusinessMappingOverwriteService vehicleBusinessMappingOverwriteService;
        private readonly IVehicleTypeService vehicleTypeService;
        private readonly IMarketingCouponService marketingCouponService;
        private readonly IMarketingCouponReceiveService marketingCouponReceiveService;
        private readonly IMarketingCouponUsingService marketingCouponUsingService;
        private readonly IFreightConfigurationExtentionService freightConfigurationExtentionService;
        private readonly IInsuredConfigService insuredConfigService;
        private readonly IPackingConfigService packingConfigService;
        private readonly IOrderData orderData;
        private readonly IOrderExtentionData orderExtentionData;
        private readonly IOrderPackingRecordData orderPackingRecordData;
        private readonly IOrderPoolData orderPoolData;
        private readonly IOrderFreightRecordData orderFreightRecordData;
        private readonly IOrderFreightFormulaRecordData orderFreightFormulaRecordData;
        private readonly IOrderExtentionGoodsChecklistData orderExtentionGoodsChecklistData;
        private readonly IOrderFreightAppendRecordData orderFreightAppendRecordData;
        private readonly IBigCustomerService bigCustomerService;
        private readonly IBigCustomerFreightConfigExtentionService bigCustomerFreightConfigExtentionService;
        public SmallPiecesOrderService(IDatabaseContext databaseContext,
            IConfiguration configuration,
            IZoneService zoneService,
            IAMapUtils aMapUtils,
            ICompanyService companyService,
            IAgentRecordService agentRecordService,
            IAgentAreaRecordService agentAreaRecordService,
            ITransportOrderService transportOrderService,
            IVehicleTransportBusinessConfigService vehicleTransportBusinessConfigService,
            IVehicleBusinessMappingOverwriteService vehicleBusinessMappingOverwriteService,
            IVehicleTypeService vehicleTypeService,
            IMarketingCouponService marketingCouponService,
            IMarketingCouponReceiveService marketingCouponReceiveService,
            IMarketingCouponUsingService marketingCouponUsingService,
            IFreightConfigurationExtentionService freightConfigurationExtentionService,
            IInsuredConfigService insuredConfigService,
            IPackingConfigService packingConfigService,
            IOrderData orderData,
            IOrderExtentionData orderExtentionData,
            IOrderPackingRecordData orderPackingRecordData,
            IOrderPoolData orderPoolData,
            IOrderFreightRecordData orderFreightRecordData,
            IOrderFreightFormulaRecordData orderFreightFormulaRecordData,
            IOrderExtentionGoodsChecklistData orderExtentionGoodsChecklistData,
            IOrderFreightAppendRecordData orderFreightAppendRecordData,
            IBigCustomerService bigCustomerService,
            IBigCustomerFreightConfigExtentionService bigCustomerFreightConfigExtentionService)
        {
            this.databaseContext = databaseContext;
            this.configuration = configuration;
            this.zoneService = zoneService;
            this.aMapUtils = aMapUtils;
            this.companyService = companyService;
            this.agentRecordService = agentRecordService;
            this.agentAreaRecordService = agentAreaRecordService;
            this.transportOrderService = transportOrderService;
            this.vehicleTransportBusinessConfigService = vehicleTransportBusinessConfigService;
            this.vehicleBusinessMappingOverwriteService = vehicleBusinessMappingOverwriteService;
            this.vehicleTypeService = vehicleTypeService;
            this.marketingCouponService = marketingCouponService;
            this.marketingCouponReceiveService = marketingCouponReceiveService;
            this.marketingCouponUsingService = marketingCouponUsingService;
            this.freightConfigurationExtentionService = freightConfigurationExtentionService;
            this.insuredConfigService = insuredConfigService;
            this.packingConfigService = packingConfigService;
            this.orderData = orderData;
            this.orderExtentionData = orderExtentionData;
            this.orderPackingRecordData = orderPackingRecordData;
            this.orderPoolData = orderPoolData;
            this.orderFreightRecordData = orderFreightRecordData;
            this.orderFreightFormulaRecordData = orderFreightFormulaRecordData;
            this.orderExtentionGoodsChecklistData = orderExtentionGoodsChecklistData;
            this.orderFreightAppendRecordData = orderFreightAppendRecordData;
            this.bigCustomerService = bigCustomerService;
            this.bigCustomerFreightConfigExtentionService = bigCustomerFreightConfigExtentionService;
        }
        #region 计算运费
        public List<OrderCostChecklistDto> CalculateShippingCost(long? userId, OrderShippingCostRequestDto requestDto)
        {
            return GetShippingCost(requestDto, userId, false, out OrderEntity orderEntity);
        }
        private List<OrderCostChecklistDto> GetShippingCost(OrderShippingCostRequestDto requestDto, long? userId, bool createOrder, out OrderEntity entity)
        {
            #region 基本检查
            if (string.IsNullOrWhiteSpace(requestDto.CountyCode))
            {
                throw new ArgumentException("出发区县不能为空!");
            }
            if (requestDto.IsBook && !requestDto.BookTime.HasValue)
            {
                throw new ArgumentException("请选择预约时间!");
            }
            if (!requestDto.ConsigneeAddress.Any())
            {
                throw new ArgumentException("目的地不能为空!");
            }
            if (requestDto.ConsigneeAddress.Any(p => string.IsNullOrWhiteSpace(p.EndCountyCode)))
            {
                throw new ArgumentException("目的地城市不能为空!");
            }
            if (requestDto.SourceType == OrderSourceType.TMS)
            {
                if ((!requestDto.GoodsWeight.HasValue && !requestDto.GoodsVolume.HasValue) && (!requestDto.GoodsLength.HasValue && !requestDto.GoodsWidth.HasValue && !requestDto.GoodsHeight.HasValue))
                {
                    throw new ArgumentException("重量与体积或长宽高不能同时为空!");
                }
            }
            else
            {
                if (!requestDto.GoodsChecklist.Any())
                {
                    throw new ArgumentException("商品清单不应为空!");
                }
            }
            if (requestDto.IsInsuredPrice && (!requestDto.InsuredPrice.HasValue || requestDto.InsuredPrice.Value == 0))
            {
                throw new ArgumentException("有保价服务时，保价金额应大于0元!");
            }

            MarketingCouponDto marketingCouponDto = null;
            if (requestDto.CouponId.HasValue && requestDto.CouponId.Value > 0)
            {
                marketingCouponDto = this.marketingCouponService.GetSingle(requestDto.CouponId.Value);
                if (marketingCouponDto == null)
                {
                    throw new ArgumentException("优惠券信息不正确!");
                }
                if (this.marketingCouponUsingService.Exists(requestDto.CouponId.Value))
                {
                    throw new ArgumentException("此优惠券已使用过，无法重复使用!");
                }
            }
            var agentAreaRecordDto = this.agentAreaRecordService.GetLastLevelByCode(requestDto.CountyCode);
            if (agentAreaRecordDto == null)
            {
                throw new ArgumentException("发货区域相关业务正在筹划中，敬请期待!");
            }

            var transportBusinessConfigViewDto = this.vehicleTransportBusinessConfigService.GetList(agentAreaRecordDto.AgentAreaRecordId, requestDto.CountyCode);
            if (!transportBusinessConfigViewDto.Any(p => p.TransportBusiness == TransportBusinessType.SmallPieces))
            {
                throw new ArgumentException("此业务正在筹划中，敬请期待!");
            }

            var zoneEntity = this.zoneService.GetFromZoneEntity(requestDto.CountyCode);
            if (zoneEntity == null || zoneEntity.provinceEntity == null || zoneEntity.cityEntity == null || zoneEntity.countyEntity == null)
            {
                throw new ArgumentException("此区域信息不正确!");
            }
            VehicleBusinessMappingDto vehicleBusinessMappingDto = null;
            FreightConfigurationExtentionDto freightConfigurationExtentionDto = null;
            if (requestDto.GoodsLength.HasValue && requestDto.GoodsWidth.HasValue && requestDto.GoodsHeight.HasValue)
            {
                var vehicleTypeList = this.vehicleTypeService.GetVehicleList(requestDto.GoodsLength.Value, requestDto.GoodsWidth.Value, requestDto.GoodsHeight.Value);
                if (!vehicleTypeList.Any())
                {
                    throw new ArgumentException("未匹配到合适装载此货物的车型!");
                }

                foreach (var vehicleTypeDto in vehicleTypeList)
                {
                    var mappingOverwriteDto = this.vehicleBusinessMappingOverwriteService.Get(TransportBusinessType.SmallPieces, vehicleTypeDto.VehicleTypeId, null, agentAreaRecordDto.AgentRecordId);
                    if (mappingOverwriteDto != null && vehicleBusinessMappingDto == null)
                    {
                        vehicleBusinessMappingDto = mappingOverwriteDto;
                    }
                }
                if (vehicleBusinessMappingDto == null)
                {
                    throw new ArgumentException("此区域未找到此业务匹配的车辆配置信息!");
                }
                freightConfigurationExtentionDto = this.freightConfigurationExtentionService.Get(vehicleBusinessMappingDto.VehicleTypeId, zoneEntity.provinceEntity.ProvinceCode, zoneEntity.cityEntity.CityCode, zoneEntity.countyEntity.CountyCode, requestDto.SourceType, requestDto.FreightType);
                if (freightConfigurationExtentionDto == null)
                {
                    throw new Exception("此区域缺少运费信息!");
                }
            }
            else if (requestDto.GoodsWeight.HasValue || requestDto.GoodsVolume.HasValue)
            {
                if (requestDto.GoodsVolume.HasValue && !requestDto.GoodsWeight.HasValue)
                {
                    requestDto.GoodsWeight = requestDto.GoodsVolume.Value / 5000;
                }
                else
                {
                    throw new ArgumentException("缺少货物重量或体积!");
                }
                freightConfigurationExtentionDto = this.freightConfigurationExtentionService.Get(requestDto.CountyCode, requestDto.GoodsWeight.Value, requestDto.SourceType, requestDto.FreightType);
                if (freightConfigurationExtentionDto == null)
                {
                    throw new Exception("此区域缺少运费信息!");
                }
                vehicleBusinessMappingDto = this.vehicleBusinessMappingOverwriteService.Get(TransportBusinessType.SmallPieces, freightConfigurationExtentionDto.VehicleTypeId, null, agentAreaRecordDto.AgentRecordId);
                if (vehicleBusinessMappingDto == null)
                {
                    throw new ArgumentException("此区域未找到此业务匹配的车辆配置信息!");
                }
            }
            if (requestDto.Packings != null && requestDto.Packings.Any())
            {
                foreach (var item in requestDto.Packings)
                {
                    var packingDto = this.packingConfigService.Get(item.PackingConfigId);
                    if (packingDto == null)
                    {
                        throw new ArgumentException("包装材料信息不正确!");
                    }
                }
            }
            #endregion

            #region 计算距离
            int endAddressCount = 0;
            int distanceTotal = 0;
            string endCountyCode = string.Empty;
            string endCityCode = string.Empty;
            string endProvinceCode = string.Empty;
            foreach (var item in requestDto.ConsigneeAddress)
            {
                endAddressCount = endAddressCount + 1;
                var endZoneEntity = this.zoneService.GetFromZoneEntity(item.EndCountyCode);
                if (endZoneEntity == null || endZoneEntity.provinceEntity == null || endZoneEntity.cityEntity == null || endZoneEntity.countyEntity == null)
                {
                    throw new ArgumentException("目的地区域信息不正确!");
                }
                var directionResponseDto = this.aMapUtils.GetDirectionDriving(new DirectionDrivingRequestDto
                {
                    Origin = new double[2] { requestDto.Longitude, requestDto.Latitude },
                    Destination = new double[2] { item.EndLongitude, item.EndLatitude }
                });
                int distance = 0;
                foreach (var path in directionResponseDto.Route.Paths)
                {
                    int len = 0;
                    if (int.TryParse(path.distance, out len))
                    {
                        distance += len;
                    }
                }
                distanceTotal += distance;
                if (endAddressCount == requestDto.ConsigneeAddress.Count)
                {
                    endCountyCode = endZoneEntity.countyEntity.CountyCode;
                    endCityCode = endZoneEntity.cityEntity.CityCode;
                    endProvinceCode = endZoneEntity.provinceEntity.ProvinceCode;
                }
            }
            if (distanceTotal > 0)
            {
                distanceTotal = distanceTotal % 1000 > 0 ? distanceTotal / 1000 + 1 : distanceTotal / 1000;
            }
            #endregion

            #region 计算重量
            decimal weight = 0;
            decimal singleWeight = 0;
            if (requestDto.SourceType == OrderSourceType.TMS)
            {
                if (requestDto.GoodsWeight.HasValue && requestDto.GoodsVolume.HasValue)
                {
                    weight = requestDto.GoodsWeight.Value > (requestDto.GoodsVolume.Value / 5000) ? requestDto.GoodsWeight.Value : (requestDto.GoodsVolume.Value / 5000);
                }
                else if (requestDto.GoodsWeight.HasValue && !requestDto.GoodsVolume.HasValue && (requestDto.GoodsLength.HasValue && requestDto.GoodsWidth.HasValue && requestDto.GoodsHeight.HasValue))
                {
                    decimal volume = requestDto.GoodsLength.Value * requestDto.GoodsWidth.Value * requestDto.GoodsHeight.Value;
                    weight = requestDto.GoodsWeight.Value > (volume / 5000) ? requestDto.GoodsWeight.Value : (volume / 5000);
                }
                else if (requestDto.GoodsWeight.HasValue && !requestDto.GoodsVolume.HasValue)
                {
                    weight = requestDto.GoodsWeight.Value;
                }
                else if (!requestDto.GoodsWeight.HasValue && requestDto.GoodsVolume.HasValue)
                {
                    weight = requestDto.GoodsVolume.Value / 5000;
                }
                singleWeight = weight;
            }
            else
            {
                foreach (var item in requestDto.GoodsChecklist)
                {

                    if (item.GoodsWeight.HasValue && item.GoodsVolume.HasValue)
                    {
                        singleWeight = item.GoodsWeight.Value > (item.GoodsVolume.Value / 5000) ? item.GoodsWeight.Value : (item.GoodsVolume.Value / 5000);
                    }
                    else if (item.GoodsWeight.HasValue && !item.GoodsVolume.HasValue && (item.GoodsLength.HasValue && item.GoodsWidth.HasValue && item.GoodsHeight.HasValue))
                    {
                        decimal volume = item.GoodsLength.Value * item.GoodsWidth.Value * item.GoodsHeight.Value;
                        singleWeight = item.GoodsWeight.Value > (volume / 5000) ? item.GoodsWeight.Value : (volume / 5000);
                    }
                    else if (item.GoodsWeight.HasValue && !item.GoodsVolume.HasValue)
                    {
                        singleWeight = item.GoodsWeight.Value;
                    }
                    else if (!item.GoodsWeight.HasValue && item.GoodsVolume.HasValue)
                    {
                        singleWeight = item.GoodsVolume.Value / 5000;
                    }
                    weight = weight + singleWeight;
                }
            }
            if ((weight * 1000) % 100 <= 50)
            {
                weight = ((weight * 1000) / 100) + 50;
            }
            else
            {
                weight = ((weight * 1000) / 100) + 100;
            }
            weight = weight / 1000;
            #endregion

            #region 大客户检测
            bool isPiecesPrice = false;
            decimal piecesPrice = 0;
            if (userId.HasValue && requestDto.SourceType == OrderSourceType.TMS)
            {
                var bigCustomerDto = this.bigCustomerService.GetByUserId(userId.Value);
                if (bigCustomerDto != null && bigCustomerDto.EnableSmallPieces)
                {
                    if (bigCustomerDto.SmallPiecesPrice.HasValue)
                    {
                        if (singleWeight < bigCustomerDto.SmallPiecesPriceMaxWeight.Value)
                        {
                            isPiecesPrice = true;
                            piecesPrice = bigCustomerDto.SmallPiecesPrice.Value;
                        }
                    }
                    else
                    {
                        var bigCustomerFreightExtentionEntity = this.bigCustomerFreightConfigExtentionService.GetByFreightExtentionId(freightConfigurationExtentionDto.FreightConfigurationExtentionId, bigCustomerDto.BigCustomerId);
                        if (bigCustomerFreightExtentionEntity != null)
                        {
                            freightConfigurationExtentionDto.FirstWeight = bigCustomerFreightExtentionEntity.FirstWeight;
                            freightConfigurationExtentionDto.MaxWeight = bigCustomerFreightExtentionEntity.MaxWeight;
                            freightConfigurationExtentionDto.StartPrice = bigCustomerFreightExtentionEntity.StartPrice;
                            freightConfigurationExtentionDto.EveryWeightPrice = bigCustomerFreightExtentionEntity.EveryWeightPrice;
                            freightConfigurationExtentionDto.SameCountyMaxMileage = bigCustomerFreightExtentionEntity.SameCountyMaxMileage;
                            freightConfigurationExtentionDto.SameCountyRatio = bigCustomerFreightExtentionEntity.SameCountyRatio;
                            freightConfigurationExtentionDto.SameCityMaxMileage = bigCustomerFreightExtentionEntity.SameCityMaxMileage;
                            freightConfigurationExtentionDto.SameCityRatio = bigCustomerFreightExtentionEntity.SameCityRatio;
                            freightConfigurationExtentionDto.SameProvinceMileage = bigCustomerFreightExtentionEntity.SameProvinceMileage;
                            freightConfigurationExtentionDto.SameProvinceRatio = bigCustomerFreightExtentionEntity.SameProvinceRatio;
                            freightConfigurationExtentionDto.MileagePrice = bigCustomerFreightExtentionEntity.MileagePrice;
                        }
                    }
                }
            }
            #endregion

            #region 保价服务
            InsuredConfigDto insuredConfigDto = null;
            OrderCostChecklistDto insuredServiceCost = new OrderCostChecklistDto();
            insuredServiceCost.CostCode = OrderCostType.InsuredServiceAmount.ToString();
            insuredServiceCost.CostTitle = OrderCostType.InsuredServiceAmount.GetDescriptionString(); //保价服务费
            insuredServiceCost.CostValue = 0;
            if (requestDto.IsInsuredPrice)
            {
                insuredConfigDto = this.insuredConfigService.Get(requestDto.InsuredConfigId.Value);
                if (insuredConfigDto == null)
                {
                    throw new ArgumentException("保价信息不正确!");
                }
                insuredServiceCost.CostValue = requestDto.InsuredPrice.Value * insuredConfigDto.InsuredFeeRatio;
            }
            #endregion

            #region 优惠券
            OrderCostChecklistDto couponServiceCost = new OrderCostChecklistDto();
            couponServiceCost.CostCode = OrderCostType.CouponAmount.ToString();
            couponServiceCost.CostTitle = OrderCostType.CouponAmount.GetDescriptionString(); //优惠券金额
            couponServiceCost.CostValue = 0;
            if (requestDto.CouponId.HasValue && requestDto.CouponId.Value > 0 && marketingCouponDto != null)
            {
                couponServiceCost.CostValue = 0 - marketingCouponDto.CouponAmount;
            }
            #endregion

            #region 计算续重金额
            //续重
            decimal surplusWeight = weight > freightConfigurationExtentionDto.FirstWeight ? weight - freightConfigurationExtentionDto.FirstWeight : 0;
            //续程金额(小件业务，续重金额为每斤价格，因此要乘以2)
            decimal surplusWeightAmount = (surplusWeight * 2) * freightConfigurationExtentionDto.EveryWeightPrice;
            //计算小件续重金额，同城或小于同城最大允许公里数以同城优惠价格计算，同省或小于同省最大允许公里数以同省优惠价格计算。
            decimal everySurplusWeightAmount = freightConfigurationExtentionDto.EveryWeightPrice;

            if (endProvinceCode != zoneEntity.provinceEntity.ProvinceCode)
            {
                if (freightConfigurationExtentionDto.SameProvinceMileage.HasValue && freightConfigurationExtentionDto.SameProvinceRatio.HasValue && distanceTotal < freightConfigurationExtentionDto.SameProvinceMileage.Value)
                {
                    everySurplusWeightAmount = freightConfigurationExtentionDto.EveryWeightPrice * freightConfigurationExtentionDto.SameProvinceRatio.Value;
                    surplusWeightAmount = (surplusWeight * 2) * everySurplusWeightAmount;
                }
            }
            else if (endCityCode != zoneEntity.cityEntity.CityCode)
            {
                if (freightConfigurationExtentionDto.SameCityMaxMileage.HasValue && freightConfigurationExtentionDto.SameCityRatio.HasValue && distanceTotal < freightConfigurationExtentionDto.SameCityMaxMileage.Value)
                {
                    everySurplusWeightAmount = freightConfigurationExtentionDto.EveryWeightPrice * freightConfigurationExtentionDto.SameCityRatio.Value;
                    surplusWeightAmount = (surplusWeight * 2) * everySurplusWeightAmount;
                }
                else if (freightConfigurationExtentionDto.SameProvinceMileage.HasValue && freightConfigurationExtentionDto.SameProvinceRatio.HasValue && distanceTotal < freightConfigurationExtentionDto.SameProvinceMileage.Value)
                {
                    everySurplusWeightAmount = freightConfigurationExtentionDto.EveryWeightPrice * freightConfigurationExtentionDto.SameProvinceRatio.Value;
                    surplusWeightAmount = (surplusWeight * 2) * everySurplusWeightAmount;
                }
            }
            else if (endCountyCode != zoneEntity.countyEntity.CountyCode)
            {
                if (freightConfigurationExtentionDto.SameCountyMaxMileage.HasValue && freightConfigurationExtentionDto.SameCountyRatio.HasValue && distanceTotal < freightConfigurationExtentionDto.SameCountyMaxMileage.Value)
                {
                    everySurplusWeightAmount = freightConfigurationExtentionDto.EveryWeightPrice * freightConfigurationExtentionDto.SameCountyRatio.Value;
                    surplusWeightAmount = (surplusWeight * 2) * everySurplusWeightAmount;
                }
                else if (freightConfigurationExtentionDto.SameCityMaxMileage.HasValue && freightConfigurationExtentionDto.SameCityRatio.HasValue && distanceTotal < freightConfigurationExtentionDto.SameCityMaxMileage.Value)
                {
                    everySurplusWeightAmount = freightConfigurationExtentionDto.EveryWeightPrice * freightConfigurationExtentionDto.SameCityRatio.Value;
                    surplusWeightAmount = (surplusWeight * 2) * everySurplusWeightAmount;
                }
                else if (freightConfigurationExtentionDto.SameProvinceMileage.HasValue && freightConfigurationExtentionDto.SameProvinceRatio.HasValue && distanceTotal < freightConfigurationExtentionDto.SameProvinceMileage.Value)
                {
                    everySurplusWeightAmount = freightConfigurationExtentionDto.EveryWeightPrice * freightConfigurationExtentionDto.SameProvinceRatio.Value;
                    surplusWeightAmount = (surplusWeight * 2) * everySurplusWeightAmount;
                }
            }
            #endregion

            #region 计算里程费用
            decimal distanceTotalAmount = freightConfigurationExtentionDto.MileagePrice.HasValue ? freightConfigurationExtentionDto.MileagePrice.Value * distanceTotal : 0;
            if (endCountyCode != zoneEntity.countyEntity.CountyCode)
            {
                distanceTotalAmount = distanceTotalAmount * 2;
            }
            #endregion

            #region 总费用
            //总费用
            decimal total = freightConfigurationExtentionDto.StartPrice + surplusWeightAmount * distanceTotalAmount;
            if (isPiecesPrice)
            {
                total = requestDto.GoodsNumber.HasValue ? requestDto.GoodsNumber.Value * piecesPrice : piecesPrice;
            }
            #endregion

            #region 包装材料
            OrderCostChecklistDto packingServiceCost = null;
            if (requestDto.Packings != null && requestDto.Packings.Any())
            {
                packingServiceCost = new OrderCostChecklistDto();
                packingServiceCost.CostCode = OrderCostType.PackingServiceAmount.ToString();
                packingServiceCost.CostTitle = OrderCostType.PackingServiceAmount.GetDescriptionString(); //包装材料费
                packingServiceCost.CostValue = requestDto.Packings.Sum(p => p.Price);
            }
            #endregion

            List<OrderCostChecklistDto> list = new List<OrderCostChecklistDto>();
            OrderCostChecklistDto orderFreightCost = new OrderCostChecklistDto();
            orderFreightCost.CostCode = OrderCostType.FreightTotal.ToString();
            orderFreightCost.CostTitle = OrderCostType.FreightTotal.GetDescriptionString(); //运费合计
            orderFreightCost.CostValue = total;
            if (!isPiecesPrice)
            {
                orderFreightCost.Checklist = new List<OrderCostChecklistDto>();
                OrderCostChecklistDto orderStartCost = new OrderCostChecklistDto();
                orderStartCost.CostCode = OrderCostType.StartPrice.ToString();
                orderStartCost.CostTitle = OrderCostType.StartPrice.GetDescriptionString(); //起步金额
                orderStartCost.CostValue = freightConfigurationExtentionDto.StartPrice;
                orderStartCost.ParentCostCode = orderFreightCost.CostCode;
                orderFreightCost.Checklist.Add(orderStartCost);
                if (surplusWeightAmount > 0)
                {
                    OrderCostChecklistDto orderSurplusCost = new OrderCostChecklistDto();
                    orderSurplusCost.CostCode = OrderCostType.SurplusWeightAmount.ToString();
                    orderSurplusCost.CostTitle = OrderCostType.SurplusWeightAmount.GetDescriptionString(); //续重金额
                    orderSurplusCost.CostValue = surplusWeightAmount;
                    orderSurplusCost.ParentCostCode = orderFreightCost.CostCode;
                    orderFreightCost.Checklist.Add(orderSurplusCost);
                }
                if (distanceTotalAmount > 0)
                {
                    OrderCostChecklistDto orderDistanceAmountCost = new OrderCostChecklistDto();
                    orderDistanceAmountCost.CostCode = OrderCostType.DistanceAmount.ToString();
                    orderDistanceAmountCost.CostTitle = OrderCostType.DistanceAmount.GetDescriptionString(); //里程金额
                    orderDistanceAmountCost.CostValue = distanceTotalAmount;
                    orderDistanceAmountCost.ParentCostCode = orderFreightCost.CostCode;
                    orderFreightCost.Checklist.Add(orderDistanceAmountCost);
                }
            }
            list.Add(orderFreightCost);

            if (insuredConfigDto != null)
            {
                list.Add(insuredServiceCost);
            }
            if (couponServiceCost.CostValue > 0)
            {
                list.Add(couponServiceCost);
            }
            if (packingServiceCost != null)
            {
                list.Add(packingServiceCost);
            }
            OrderCostChecklistDto orderCostTotal = new OrderCostChecklistDto();
            orderCostTotal.CostCode = OrderCostType.OrderTotal.ToString();
            orderCostTotal.CostTitle = OrderCostType.OrderTotal.GetDescriptionString(); //订单合计
            orderCostTotal.CostValue = orderFreightCost.CostValue + couponServiceCost.CostValue + insuredServiceCost.CostValue + (packingServiceCost != null ? packingServiceCost.CostValue : 0);
            list.Add(orderCostTotal);
            #region 订单信息预设            
            entity = new OrderEntity();
            if (createOrder)
            {
                entity.VehicleBusinessMappingId = vehicleBusinessMappingDto.VehicleBusinessMappingId;
                entity.VehicleTypeId = vehicleBusinessMappingDto.VehicleTypeId;
                entity.VehicleTypeName = vehicleBusinessMappingDto.VehicleTypeName;
                string address = requestDto.Address;
                string zoneName = string.Format("{0}{1}{2}", zoneEntity.provinceEntity.ProvinceName, zoneEntity.cityEntity.CityName, zoneEntity.countyEntity.CountyName);
                address = address.Replace(zoneName, "");
                zoneName = string.Format("{0}{1}", zoneEntity.provinceEntity.ProvinceName, zoneEntity.countyEntity.CountyName);
                address = address.Replace(zoneName, "");
                entity.ShippingAddress = address;
                entity.ProvinceCode = zoneEntity.provinceEntity.ProvinceCode;
                entity.ProvinceName = zoneEntity.provinceEntity.ProvinceName;
                entity.CityCode = zoneEntity.cityEntity.CityCode;
                entity.CityName = zoneEntity.cityEntity.CityName;
                entity.CountyCode = zoneEntity.countyEntity.CountyCode;
                entity.CountyName = zoneEntity.countyEntity.CountyName;
                entity.Longitude = requestDto.Longitude;
                entity.Latitude = requestDto.Latitude;
                entity.FreightConfigurationExtentionId = freightConfigurationExtentionDto.FreightConfigurationExtentionId;
                entity.StartPrice = freightConfigurationExtentionDto.StartPrice;
                entity.StartWeight = Convert.ToInt32(freightConfigurationExtentionDto.FirstWeight * 1000);
                entity.ContinueWeight = Convert.ToInt32(surplusWeight * 1000);
                entity.ContinueWeightPrice = everySurplusWeightAmount;
                entity.ContinueWeightAmount = surplusWeightAmount;
                entity.ContinueMileage = distanceTotal * 1000;    //小件下续程则为全里程长度
                entity.ContinueMileagePrice = freightConfigurationExtentionDto.MileagePrice;
                entity.ContinueMileageAmount = distanceTotalAmount;
                entity.MarketingCouponId = requestDto.CouponId.HasValue && requestDto.CouponId.Value > 0 ? requestDto.CouponId.Value : new Nullable<long>();
                entity.CouponAmount = couponServiceCost.CostValue;
                entity.OrderAmount = orderCostTotal.CostValue;
                entity.FreightCostAmount = orderFreightCost.CostValue;
                entity.TotalDistanceLength = distanceTotal;

                var agentRecordDto = this.agentRecordService.Get(agentAreaRecordDto.AgentRecordId);
                entity.AgentRecordId = agentRecordDto.AgentRecordId;
                entity.CompanyId = agentRecordDto.CompanyId;
                if (agentRecordDto.AgentLevel == 3)
                {
                    if (agentRecordDto.ParentCompanyId != 1)
                    {
                        var twoAgentRecordDto = this.agentRecordService.GetByCompanyId(agentRecordDto.ParentCompanyId);
                        if (twoAgentRecordDto != null)
                        {
                            entity.TwoAgentRecordId = twoAgentRecordDto.AgentRecordId;
                            if (twoAgentRecordDto.ParentCompanyId != 1)
                            {
                                var oneAgentRecordDto = this.agentRecordService.GetByCompanyId(twoAgentRecordDto.ParentCompanyId);
                                if (oneAgentRecordDto != null)
                                {
                                    entity.OneAgentRecordId = oneAgentRecordDto.AgentRecordId;
                                }
                            }
                        }
                    }
                }
                else if (agentRecordDto.ParentCompanyId != 1)
                {
                    var oneAgentRecordDto = this.agentRecordService.GetByCompanyId(agentRecordDto.ParentCompanyId);
                    if (oneAgentRecordDto != null)
                    {
                        entity.OneAgentRecordId = oneAgentRecordDto.AgentRecordId;
                    }
                }
                if (requestDto.IsInsuredPrice)
                {
                    entity.InsuredConfigId = insuredConfigDto.InsuredConfigId;
                    entity.InsuredPrice = insuredServiceCost.CostValue;
                    entity.InsuredPriceAmount = insuredServiceCost.CostValue;
                    entity.InsuredPriceChargeAmount = insuredServiceCost.CostValue;
                }
                if (requestDto.IsCod)
                {
                    entity.CodCost = requestDto.CodCost;
                    entity.CodCostAmount = requestDto.CodCost;
                }
            }
            #endregion
            return list;
        }
        #endregion

        #region 下单
        #region 检查信息
        private void CheckOrderRequestInfo(SmallPiecesOrderRequestDto orderRequestDto)
        {
            string[] imageSuffixes = new string[] { "jpg", "jpeg" };
            #region 必要检查
            if (!orderRequestDto.GoodsAddress.Any())
            {
                throw new ArgumentException("请填写货物及目的地信息及联系信息");
            }
            if (!orderRequestDto.GoodsAddress.Any(p => p.AddressType == AddressType.Place))
            {
                throw new ArgumentException("请填写卸货地址信息及联系信息");
            }
            if (string.IsNullOrWhiteSpace(orderRequestDto.ShippingAddress) || string.IsNullOrWhiteSpace(orderRequestDto.Shipping) || string.IsNullOrWhiteSpace(orderRequestDto.ShippingPhone))
            {
                throw new ArgumentException("请填写装货地址信息及联系信息");
            }
            if (orderRequestDto.GoodsAddress.Any(p => !p.GoodsWeight.HasValue && !p.GoodsVolume.HasValue))
            {
                throw new ArgumentException("请填写货物重量或体积");
            }
            #endregion

            #region 检查额外服务

            if (orderRequestDto.IsInsuredPrice)
            {
                if (!orderRequestDto.InsuredPrice.HasValue)
                {
                    throw new ArgumentException("请输入保价金额");
                }
                /* 
                if (string.IsNullOrWhiteSpace(orderRequestDto.InsuredPriceCertificates))
                {
                    throw new ArgumentException("请上传保价货物价值证明");
                }

                if (!imageSuffixes.Contains(orderRequestDto.InsuredPriceCertificates.Substring(orderRequestDto.InsuredPriceCertificates.LastIndexOf(".") + 1)))
                {
                    throw new ArgumentException("请上传保价货物价值证明");
                }
                */
            }
            if (orderRequestDto.IsCod)
            {
                if (!orderRequestDto.CodCost.HasValue)
                {
                    throw new ArgumentException("请输入代收货款金额");
                }
                /*
                if (string.IsNullOrWhiteSpace(orderRequestDto.CodGoodsValueCertificates))
                {
                    throw new ArgumentException("请上代收货款价值凭证");
                }
                if (!imageSuffixes.Contains(orderRequestDto.CodGoodsValueCertificates.Substring(orderRequestDto.CodGoodsValueCertificates.LastIndexOf(".") + 1)))
                {
                    throw new ArgumentException("请上代收货款价值凭证");
                }
                */
            }
            #endregion 检查额外服务
        }
        #endregion
        public OrderDto Create(OrderBaseRequestDto requestDto, long userId, long? transportOrderId)
        {
            SmallPiecesOrderRequestDto dto = (SmallPiecesOrderRequestDto)requestDto;

            this.CheckOrderRequestInfo(dto);

            if (!dto.CouponId.HasValue && requestDto.CouponId.Value > 0)
            {
                if (!this.marketingCouponReceiveService.Exists(userId, dto.CouponId.Value))
                {
                    throw new ArgumentException("此优惠券不属于您!");
                }
            }
            TransformOrderShippingCostService transformOrderShippingCostService = new TransformOrderShippingCostService();
            OrderShippingCostRequestDto shippingCostRequestDto = transformOrderShippingCostService.GetRequestDto(dto, null, null);
            if (dto.Packings != null && dto.Packings.Any())
            {
                shippingCostRequestDto.Packings = dto.Packings;
            }
            var shippingCostList = this.GetShippingCost(shippingCostRequestDto, userId, true, out OrderEntity entity);
            var orderFreightRecordList = transformOrderShippingCostService.GetOrderFreightRecords(shippingCostList);

            var companyDto = this.companyService.Get(entity.CompanyId.Value);

            TransportOrderRequestDto transportOrderRequestDto = new TransportOrderRequestDto();
            transportOrderRequestDto.TransportOrderNo = RandomCode.GetOrderNo("YSTMSTO", new SnowflakeWorker(int.Parse(configuration["Snowflake:DatacenterId"]), int.Parse(configuration["Snowflake:ServerId"])).NextId());
            transportOrderRequestDto.SourceType = dto.SourceType;
            transportOrderRequestDto.UserId = userId;
            transportOrderRequestDto.IsBook = dto.IsBook;
            transportOrderRequestDto.BookTime = dto.BookTime;
            transportOrderRequestDto.IsSplitOrder = false;
            transportOrderRequestDto.TransportAmount = shippingCostList.Single(p => p.CostCode == OrderCostType.FreightTotal.ToString()).CostValue;
            transportOrderRequestDto.CountyCode = dto.CountyCode;
            transportOrderRequestDto.CountyCode = dto.CountyCode;
            transportOrderRequestDto.Longitude = dto.Longitude;
            transportOrderRequestDto.Latitude = dto.Latitude;

            var endAddressInfo = dto.GoodsAddress.Where(p => p.AddressType == AddressType.Place).Last();
            transportOrderRequestDto.EndCountyCode = endAddressInfo.EndCountyCode;
            transportOrderRequestDto.EndLongitude = endAddressInfo.EndLongitude;
            transportOrderRequestDto.EndLatitude = endAddressInfo.EndLatitude;
            var orderExtentionList = dto.GoodsAddress.Where(p => p.AddressType == AddressType.Place).OrderBy(p => p.EndIndex);

            var shippingGoodsInfo = dto.GoodsAddress.Where(p => p.AddressType == AddressType.Take).OrderBy(p => p.EndIndex).First();

            List<OrderExtentionEntity> orderExtentionEntities = new List<OrderExtentionEntity>();
            OrderExtentionEntity orderExtentionShippingEntity = new OrderExtentionEntity();
            orderExtentionShippingEntity.Consignee = dto.Shipping;
            orderExtentionShippingEntity.ConsigneePhone = dto.ShippingPhone;
            orderExtentionShippingEntity.EndAddress = entity.ShippingAddress;
            orderExtentionShippingEntity.AddressType = AddressType.Take.ToString();
            orderExtentionShippingEntity.EndProvinceCode = entity.ProvinceCode;
            orderExtentionShippingEntity.EndProvinceName = entity.ProvinceName;
            orderExtentionShippingEntity.EndCityCode = entity.CityCode;
            orderExtentionShippingEntity.EndCityName = entity.CityName;
            orderExtentionShippingEntity.EndCountyCode = entity.CountyCode;
            orderExtentionShippingEntity.EndCountyName = entity.CountyName;
            orderExtentionShippingEntity.EndLongitude = entity.Longitude;
            orderExtentionShippingEntity.EndLatitude = entity.Latitude;
            orderExtentionShippingEntity.GoodsCount = shippingGoodsInfo.GoodsCount;
            orderExtentionShippingEntity.GoodsUnit = shippingGoodsInfo.GoodsUnit;
            orderExtentionShippingEntity.GoodsSku = shippingGoodsInfo.GoodsSku;
            orderExtentionShippingEntity.GoodsName = shippingGoodsInfo.GoodsName;
            orderExtentionShippingEntity.GoodsPhoto = shippingGoodsInfo.GoodsPhoto;
            orderExtentionShippingEntity.GoodsWeight = shippingGoodsInfo.GoodsWeight;
            orderExtentionShippingEntity.GoodsVolume = shippingGoodsInfo.GoodsVolume;
            orderExtentionShippingEntity.GoodsWidth = shippingGoodsInfo.GoodsWidth;
            orderExtentionShippingEntity.GoodsLength = shippingGoodsInfo.GoodsLength;
            orderExtentionShippingEntity.GoodsHeight = shippingGoodsInfo.GoodsHeight;
            orderExtentionShippingEntity.CreateTime = DateTime.Now;
            orderExtentionEntities.Add(orderExtentionShippingEntity);
            foreach (var item in orderExtentionList)
            {
                ZoneEntity zoneEntity = this.zoneService.GetFromZoneEntity(item.EndCountyCode);
                if (zoneEntity == null || zoneEntity.provinceEntity == null || zoneEntity.cityEntity == null || zoneEntity.countyEntity == null)
                {
                    throw new ArgumentException("地址未能匹配到正确的地址信息，请联系客服");
                }
                string address = item.EndAddress;
                string zoneName = string.Format("{0}{1}{2}", zoneEntity.provinceEntity.ProvinceName, zoneEntity.cityEntity.CityName, zoneEntity.countyEntity.CountyName);
                address = address.Replace(zoneName, "");
                zoneName = string.Format("{0}{1}", zoneEntity.provinceEntity.ProvinceName, zoneEntity.countyEntity.CountyName);
                address = address.Replace(zoneName, "");

                OrderExtentionEntity orderExtentionEntity = item.As<OrderExtentionEntity>();
                orderExtentionEntity.Consignee = item.Consignee;
                orderExtentionEntity.ConsigneePhone = item.ConsigneePhone;
                orderExtentionEntity.CreateTime = DateTime.Now;
                orderExtentionEntity.EndIndex = item.EndIndex;
                orderExtentionEntity.EndAddress = address;
                orderExtentionEntity.EndProvinceCode = zoneEntity.provinceEntity.ProvinceCode;
                orderExtentionEntity.EndCityCode = zoneEntity.cityEntity.CityCode;
                orderExtentionEntity.EndCountyCode = zoneEntity.countyEntity.CountyCode;
                orderExtentionEntity.EndProvinceName = zoneEntity.provinceEntity.ProvinceName;
                orderExtentionEntity.EndCityName = zoneEntity.cityEntity.CityName;
                orderExtentionEntity.EndCountyName = zoneEntity.countyEntity.CountyName;
                orderExtentionEntities.Add(orderExtentionEntity);
                if (item.EndIndex.Equals(orderExtentionList.Max(p => p.EndIndex)))
                {
                    entity.EndProvinceCode = zoneEntity.provinceEntity.ProvinceCode;
                    entity.EndCityCode = zoneEntity.cityEntity.CityCode;
                    entity.EndCountyCode = zoneEntity.countyEntity.CountyCode;
                    entity.EndProvinceName = zoneEntity.provinceEntity.ProvinceName;
                    entity.EndCityName = zoneEntity.cityEntity.CityName;
                    entity.EndCountyName = zoneEntity.countyEntity.CountyName;
                    entity.EndLongitude = item.EndLongitude;
                    entity.EndLatitude = item.EndLatitude;
                }
            }
            var orderExtentionGoodsChecklistEntities = dto.GoodsChecklist.As<List<OrderExtentionGoodsChecklistEntity>>();
            this.databaseContext.BeginTransaction();

            TransportOrderDto transportOrderDto = null;
            if (!transportOrderId.HasValue)
            {
                transportOrderDto = this.transportOrderService.Add(transportOrderRequestDto);
            }
            else
            {
                transportOrderDto = this.transportOrderService.Get(transportOrderId.Value);
            }

            #region 订单信息
            entity.CompanyName = companyDto.CompanyName;
            #region 订单基本信息
            entity.OrderNo = RandomCode.GetOrderNo("YSTMSSPO", new SnowflakeWorker(int.Parse(configuration["Snowflake:DatacenterId"]), int.Parse(configuration["Snowflake:ServerId"])).NextId());
            entity.TransportOrderId = transportOrderDto.TransportOrderId;
            entity.TransportOrderNo = transportOrderDto.TransportOrderNo;
            entity.SourceType = requestDto.SourceType.ToString();
            //TODO:大客户完成后，需要增加大客户价格检查。
            //entity.IsVip = 
            entity.UserId = dto.UserId;
            entity.Shipping = dto.Shipping;
            entity.ShippingPhone = dto.ShippingPhone;
            entity.ShippingAddress = dto.ShippingAddress;
            entity.Consignee = endAddressInfo.Consignee;
            entity.ConsigneeAddress = endAddressInfo.EndAddress;
            entity.ConsigneePhone = endAddressInfo.ConsigneePhone;
            entity.TakeGoodsCode = RandomCode.GenerateUniqueCode();
            entity.GoodsPhoto = string.Join(",", dto.GoodsAddress.Where(p => p.AddressType == AddressType.Place).Select(p => p.GoodsPhoto));
            entity.GoodsName = string.Join(",", dto.GoodsAddress.Where(p => p.AddressType == AddressType.Place).Distinct().Select(p => p.GoodsName));
            entity.GoodsWeight = endAddressInfo.GoodsWeight;
            entity.GoodsVolume = endAddressInfo.GoodsVolume;
            entity.GoodsLength = endAddressInfo.GoodsLength;
            entity.GoodsWidth = endAddressInfo.GoodsWidth;
            entity.GoodsHeight = endAddressInfo.GoodsHeight;

            entity.PayMode = dto.PayMode;
            entity.IsBook = dto.IsBook;
            entity.BookTime = dto.BookTime;
            #endregion
            #region 订单运输信息及套餐信息
            entity.VehicleTransportBusinessConfigId = dto.VehicleTransportBusinessConfigId;
            entity.TransportBusiness = dto.VehicleTransportBusinessType.ToString();
            entity.TransportBusinessStr = dto.VehicleTransportBusinessType.GetDescriptionString();
            #endregion

            #region 给司机捎句话及高德配置
            entity.DriverRemark = dto.DriverRemark;
            entity.MapTruckModeId = 0;
            entity.MapTruckTypeId = 0;
            #endregion

            #region 小件专有
            entity.IsInsuredContact = dto.IsInsuredContact;
            entity.BookArrivalTime = dto.BookArrivalTime;
            entity.AgentBranchesConfigId = dto.AgentBranchesConfigId;
            #endregion
            #endregion

            List<OrderPackingRecordEntity> orderPackingRecordEntities = null;
            if (dto.Packings != null && dto.Packings.Any())
            {
                orderPackingRecordEntities = dto.Packings.As<List<OrderPackingRecordEntity>>();
            }
            var orderEntity = this.orderData.Add(entity).GetAwaiter().GetResult();
            if (orderEntity == null)
            {
                throw new ArgumentException("下单失败!");
            }
            var orderPoolEntity = entity.As<OrderPoolEntity>();
            orderPoolEntity.OrderId = orderEntity.OrderId;

            var agentRecordDto = this.agentRecordService.Get(entity.AgentRecordId);
            orderPoolEntity.AssignTimeOut = DateTime.Now.AddSeconds(agentRecordDto.ManualAssignWaitTime);
            orderPoolEntity.AssignType = agentRecordDto.EnabledManualAssign ? OrderAssignType.Manual : OrderAssignType.Auto;
            orderPoolEntity.IsAssignReady = entity.PayMode != PayMode.CurrentlyPay;

            var prderPoolResult = this.orderPoolData.Add(orderPoolEntity).GetAwaiter().GetResult();
            if (prderPoolResult == null)
            {
                throw new ArgumentException("下单失败!");
            }
            foreach (var item in orderExtentionEntities)
            {
                item.OrderId = orderEntity.OrderId;
                item.OrderNo = orderEntity.OrderNo;
                item.CreateTime = DateTime.Now;
            }

            if (!this.orderExtentionData.Add(orderExtentionEntities).GetAwaiter().GetResult())
            {
                throw new ArgumentException("下单失败!");
            }

            if (orderExtentionGoodsChecklistEntities != null && orderExtentionGoodsChecklistEntities.Any())
            {
                foreach (var item in orderExtentionGoodsChecklistEntities)
                {
                    item.OrderId = orderEntity.OrderId;
                    item.OrderNo = orderEntity.OrderNo;
                    item.CreateTime = DateTime.Now;
                }
                if (!this.orderExtentionGoodsChecklistData.Add(orderExtentionGoodsChecklistEntities).GetAwaiter().GetResult())
                {
                    throw new ArgumentException("下单失败!");
                }
            }

            if (orderPackingRecordEntities != null)
            {
                foreach (var item in orderPackingRecordEntities)
                {
                    item.OrderId = orderEntity.OrderId;
                    item.OrderNo = orderEntity.OrderNo;
                    item.CreateTime = DateTime.Now;
                }
                if (!this.orderPackingRecordData.Add(orderPackingRecordEntities).GetAwaiter().GetResult())
                {
                    throw new ArgumentException("下单失败!");
                }
            }

            foreach (var item in orderFreightRecordList)
            {
                item.OrderId = orderEntity.OrderId;
                item.OrderNo = orderEntity.OrderNo;
                item.IsOrderNewFreight = true;
                item.CreateTime = DateTime.Now;
            }
            if (!this.orderFreightRecordData.Add(orderFreightRecordList).GetAwaiter().GetResult())
            {
                throw new ArgumentException("下单失败!");
            }
            var freightFormulaRecordEntity = orderEntity.As<OrderFreightFormulaRecordEntity>();
            freightFormulaRecordEntity.RecordTimes = 1;
            freightFormulaRecordEntity.CreateTime = DateTime.Now;
            var freightFormulaRecordResult = this.orderFreightFormulaRecordData.Add(freightFormulaRecordEntity).GetAwaiter().GetResult();
            if (freightFormulaRecordResult == null)
            {
                throw new ArgumentException("下单失败!");
            }

            var orderDto = orderEntity.As<OrderDto>();

            this.databaseContext.Commit();
            return orderDto;
        }
        #endregion

        #region 负重
        public OrderFreightAppendRecordDto ChangeWeight(OrderChangeWeightRequestDto dto)
        {
            OrderDto orderDto = orderData.GetEntity(dto.OrderNo).GetAwaiter().GetResult().As<OrderDto>();
            if (orderDto == null)
            {
                throw new ArgumentException("订单信息不存在");
            }
            if (orderDto.OrderStatus == OrderStatus.Cancel)
            {
                throw new ArgumentException("订单已取消，无法完成负重操作");
            }
            if (orderDto.OrderStatus == OrderStatus.Complete)
            {
                throw new ArgumentException("订单已完成，无法完成负重操作");
            }
            if (orderDto.OrderStatus == OrderStatus.Dispatching)
            {
                throw new ArgumentException("订单未指派车辆，无法完成负重操作");
            }
            if (orderDto.VehicleTypeId != dto.Driver.VehicleTypeId)
            {
                throw new ArgumentException("您无法操作其他司机订单");
            }
            if (dto.Weight == default(int) && (dto.Length == default(decimal) && dto.Width == default(decimal) && dto.Height == default(decimal)))
            {
                throw new ArgumentException("复称物品重量或物品尺寸不能为空！");
            }
            int weight = (int)Math.Max(dto.Weight, dto.Length * dto.Width * dto.Height * 100 * 100 * 100 / 4500);
            OrderEntity orderEntity = orderDto.As<OrderEntity>();
            orderEntity.GoodsWeight = dto.Weight;
            orderEntity.GoodsLength = dto.Length;
            orderEntity.GoodsWidth = dto.Width;
            orderEntity.GoodsHeight = dto.Height;
            orderEntity.GoodsVolume = (dto.Length * 100 * dto.Width * 100 * dto.Height * 100) / 4500;
            //重新计算运费
            OrderShippingCostRequestDto shippingCostRequestDto = new OrderShippingCostRequestDto();
            shippingCostRequestDto.Address = orderDto.ConsigneeAddress;
            shippingCostRequestDto.TransportBusinessType = orderDto.TransportBusiness.As<TransportBusinessType>();

            #region 预约信息
            shippingCostRequestDto.IsBook = orderDto.IsBook;
            shippingCostRequestDto.BookTime = orderDto.BookTime;
            #endregion

            #region 基本信息
            shippingCostRequestDto.SourceType = orderDto.SourceType.As<OrderSourceType>();
            shippingCostRequestDto.FreightType = orderDto.FreightType.As<FreightType>();
            shippingCostRequestDto.UserId = orderDto.UserId;
            shippingCostRequestDto.VehicleTypeId = orderDto.VehicleTypeId;

            #endregion
            shippingCostRequestDto.GoodsNumber = orderDto.BigGoodsNumber;
            shippingCostRequestDto.GoodsWeight = weight;
            shippingCostRequestDto.GoodsVolume = (dto.Length * 100 * dto.Width * 100 * dto.Height * 100) / 4500;
            shippingCostRequestDto.GoodsLength = dto.Length;
            shippingCostRequestDto.GoodsWidth = dto.Width;
            shippingCostRequestDto.GoodsHeight = dto.Height;
            shippingCostRequestDto.CountyCode = orderDto.CountyCode;
            shippingCostRequestDto.Longitude = orderDto.Longitude;
            shippingCostRequestDto.Latitude = orderDto.Latitude;
            shippingCostRequestDto.IsInsuredPrice = orderDto.IsInsuredPrice;
            shippingCostRequestDto.IsCod = orderDto.IsCod;
            #region 打赏金额
            shippingCostRequestDto.GratuityAmount = orderDto.MusangAmount;
            #endregion

            #region 保价服务详细信息
            shippingCostRequestDto.InsuredConfigId = orderDto.InsuredConfigId;
            shippingCostRequestDto.InsuredPriceCertificates = orderDto.InsuredPriceCertificates;
            shippingCostRequestDto.InsuredPrice = orderDto.InsuredPrice;
            #endregion

            #region 代收货款服务
            shippingCostRequestDto.CodCost = orderDto.CodCost;
            #endregion

            #region 优惠券信息
            shippingCostRequestDto.CouponId = orderDto.MarketingCouponId;
            #endregion

            if (orderDto.SpecificServiceAmount.HasValue && orderDto.SpecificServiceAmount.Value > 0)
            {
                shippingCostRequestDto.SpecificService = new List<OrderSpecificServiceRequestDto>();
            }

            shippingCostRequestDto.ConsigneeAddress = this.orderExtentionData.GetList(orderDto.OrderId).GetAwaiter().GetResult().Where(p => p.AddressType == AddressType.Place.ToString()).As<List<OrderShippingCostAddressRequestDto>>();

            if (shippingCostRequestDto.TransportBusinessType == TransportBusinessType.RunErrands || shippingCostRequestDto.TransportBusinessType == TransportBusinessType.SmallPieces)
            {
                shippingCostRequestDto.GoodsChecklist = this.orderExtentionGoodsChecklistData.GetList(orderDto.OrderId).GetAwaiter().GetResult().As<List<OrderShippingCostGoodsRequestDto>>();
            }

            var changeWeightCost = this.GetShippingCost(shippingCostRequestDto, orderDto.UserId, true, out OrderEntity outOrderEntity);
            var oldCost = this.orderFreightRecordData.GetList(orderDto.OrderId).GetAwaiter().GetResult();
            if (oldCost.Any(p => p.CostCode == OrderCostType.OrderTotal.ToString()) && oldCost.Single(p => p.CostCode == OrderCostType.OrderTotal.ToString()).CostValue > 0)
            {
                if (changeWeightCost.Single(p => p.CostCode == OrderCostType.OrderTotal.ToString()).CostValue > oldCost.Single(p => p.CostCode == OrderCostType.OrderTotal.ToString()).CostValue)
                {
                    var latestFormulaRecords = this.orderFreightFormulaRecordData.GetList(orderDto.OrderId).GetAwaiter().GetResult();
                    OrderFreightAppendRecordEntity difference = new OrderFreightAppendRecordEntity();
                    difference.OrderId = orderDto.OrderId;
                    difference.OrderNo = orderDto.OrderNo;
                    difference.SecendWeighingDifference = changeWeightCost.Single(p => p.CostCode == OrderCostType.OrderTotal.ToString()).CostValue - oldCost.Single(p => p.CostCode == OrderCostType.OrderTotal.ToString()).CostValue;
                    databaseContext.BeginTransaction();
                    var result = this.orderFreightAppendRecordData.Add(difference).GetAwaiter().GetResult().As<OrderFreightAppendRecordDto>();
                    if (result == null)
                    {
                        throw new ArgumentException("重算运费失败!");
                    }
                    var freightFormulaRecordEntity = outOrderEntity.As<OrderFreightFormulaRecordEntity>();
                    freightFormulaRecordEntity.RecordTimes = 1;
                    freightFormulaRecordEntity.CreateTime = DateTime.Now;
                    if (latestFormulaRecords.Any())
                    {
                        var first = latestFormulaRecords.OrderByDescending(p => p.RecordTimes).First();
                        freightFormulaRecordEntity.RecordTimes = first.RecordTimes + 1;
                    }

                    var freightFormulaRecordResult = this.orderFreightFormulaRecordData.Add(freightFormulaRecordEntity).GetAwaiter().GetResult();
                    if (freightFormulaRecordResult == null)
                    {
                        throw new ArgumentException("重算运费失败!");
                    }
                    databaseContext.Commit();
                    TransformOrderShippingCostService transformOrderShippingCostService = new TransformOrderShippingCostService();
                    result.OldChecklist = transformOrderShippingCostService.GetOrderCostChecklistByOrderFreightRecord(oldCost);
                    result.NewChecklist = changeWeightCost;
                    return result;
                }
            }
            return new OrderFreightAppendRecordDto { SecendWeighingDifference = 0 };
        }
        #endregion
    }
}
